package pkt

import (
	"fmt"
	"strings"

	"github.com/google/gopacket"

	"github.com/google/gopacket/layers"

	"LterServer/model"
)

type ProPacket struct {
}

func NewProPacket() *ProPacket {
	c := new(ProPacket)
	return c
}

func (c *ProPacket) Proc(pProPacketData *model.ProPacketData) {
	var goPacket gopacket.Packet
	var ipLayer gopacket.Layer

	if pProPacketData.IPVersion == 4 {
		goPacket = gopacket.NewPacket(pProPacketData.Data, layers.LayerTypeIPv4, gopacket.NoCopy)

		ipLayer = goPacket.Layer(layers.LayerTypeIPv4)
		if ipLayer != nil {
			ip, _ := ipLayer.(*layers.IPv4)

			pProPacketData.SrcIP = ip.SrcIP.String()
			pProPacketData.DstIP = ip.DstIP.String()
		}

	} else if pProPacketData.IPVersion == 6 {
		goPacket = gopacket.NewPacket(pProPacketData.Data, layers.LayerTypeIPv6, gopacket.NoCopy)

		ipLayer = goPacket.Layer(layers.LayerTypeIPv6)
		if ipLayer != nil {
			ip, _ := ipLayer.(*layers.IPv6)

			pProPacketData.SrcIP = ip.SrcIP.String()
			pProPacketData.DstIP = ip.DstIP.String()
		}
	}

	// Let's see if the packet is TCP
	tcpLayer := goPacket.Layer(layers.LayerTypeTCP)
	if tcpLayer != nil {
		tcp, _ := tcpLayer.(*layers.TCP)

		pProPacketData.SrcPort = int(tcp.SrcPort)
		pProPacketData.DstPort = int(tcp.DstPort)
		pProPacketData.BaseProtocol = model.BASE_PROTOCOL_TCP

	} else {
		// Let's see if the packet is UDP
		udpLayer := goPacket.Layer(layers.LayerTypeUDP)
		if udpLayer != nil {
			udp, _ := udpLayer.(*layers.UDP)

			pProPacketData.SrcPort = int(udp.SrcPort)
			pProPacketData.DstPort = int(udp.DstPort)
			pProPacketData.BaseProtocol = model.BASE_PROTOCOL_UDP
		}
	}

	// Iterate over all layers, printing out each layer type
	/*gogo.LogInfo("All packet layers:")
	for _, layer := range pProPacketData.Packet.Layers() {
		gogo.LogInfo("- ", layer.LayerType())
	}*/

	// When iterating through packet.Layers() above,
	// if it lists Payload layer then that is the same as
	// this ApplicationLayer. ApplicationLayer contains the payload
	ApplicationLayer := goPacket.ApplicationLayer()
	if ApplicationLayer != nil {
		//gogo.LogDebugF("Application layer/Payload found: %s\n", ApplicationLayer.Payload())

		// Search for a string inside the payload
		if strings.Contains(string(ApplicationLayer.Payload()), "HTTP") {
			pProPacketData.AppProtocol = model.APP_PROTOCOL_HTTP
		}
	}

	// Check for errors
	if err := goPacket.ErrorLayer(); err != nil {
		fmt.Printf("Error decoding some part of the packet: % x\n", ApplicationLayer.Payload())
	}
}
